#include "HttpServer.hpp"
#include "Err.hpp"
#include "Util.hpp"
#include <memory>
#include <vector>

const std::string SEP = "\r\n";

// const std::string path = "./wwwroot/index.html";

// // 一般一个webserver，不做特殊说明，如果用户之间默认访问‘/’, 我们绝对不能把整站给对方
// // 需要添加默认首页！！而且，不能让用户访问wwwroot里面的任何一个目录本身，也可以给每一个目录都带上一个默认首页！
const std::string defaultHomePage = "index.html"; // 默认首页
const std::string webRoot = "./wwwroot";//web根目录


class HttpRequest //
{
public:
    HttpRequest() : path_(webRoot)
    {
    }

    ~HttpRequest() {}

    void Print()
    {
        logMessage(Debug, "method: %s, url: %s, version: %s",
                   method_.c_str(), url_.c_str(), httpVersion_.c_str());
        for (const auto &line : body_)
            logMessage(Debug, "-%s", line.c_str());
        logMessage(Debug, "path: %s", path_.c_str());
        logMessage(Debug, "suffix_: %s", suffix_.c_str());
    }

public:
    std::string method_;            // 请求方法
    std::string url_;               // 请求什么资源
    std::string httpVersion_;       // 请求版本
    std::vector<std::string> body_; // 变成结构体数据

    std::string path_; // 真正想访问的资源

    std::string suffix_;//后缀
};

HttpRequest Deserialize(std::string &message) // 把字符串反序列化解释成HttpRequest
{
    HttpRequest req;
    std::string line = Util::ReadOneLine(message, SEP);                       // 读第一行，循环式调用，读第一行，第二行，第三行，直到空行，就可以把报头放到vector里了
    Util::ParseRequestLine(line, &req.method_, &req.url_, &req.httpVersion_); // 解析他的请求行

    while (!message.empty()) // 继续读取，把massage读完了，就解析完了
    {
        line = Util::ReadOneLine(message, SEP);
        req.body_.push_back(line);
    }

    req.path_ += req.url_; //"wwwroot/a/b/c.html"
    if (req.path_[req.path_.size() - 1] == '/')
        req.path_ += defaultHomePage; // 请求过来只有一个'/'就自动拼接一个默认首页

    auto pos = req.path_.rfind(".");
    if (pos == std::string::npos)
        req.suffix_ = ".html";
    else
        req.suffix_ = req.path_.substr(pos);//从找到的位置，截取到结尾
    return req;
}

std::string GetContentType(const std::string &suffix)
{
    std::string content_type = "Content-Type: ";
    if (suffix == ".html" || suffix == ".htm")
        content_type + "text/html";
    else if (suffix == ".css")
        content_type += "text/css";
    else if (suffix == ".js")
        content_type += "application/x-javascript";
    else if (suffix == ".png")
        content_type += "image/png";
    else if (suffix == ".jpg")
        content_type += "image/jpeg";
    else
    {
    }
    return content_type + SEP;
}

std::string HandlerHttp(std::string &message) // 收到一个请求，我无脑给你响应
{
    // 1. 读取请求
    // 确信，request一定是一个完整的http请求报文
    // 给别人返回的是一个http response
    std::cout << "----------------------------------------" << std::endl;
    std::cout << message << std::endl;
    // 只要找到哪一行是空行，就说明把报头读完了，可是我怎么知道有效载荷有多大呢？
    // 所以，请求和响应中报头有一个属性：Content-Length：Body的长度
    // 2. 反序列化和分析请求
    // 下一步，他要什么，我给他什么，不是我无脑给你响应，去指定的wwwroot目录下，去找请求的资源所以有了反序列化
    HttpRequest req = Deserialize(message);
    req.Print();
    // 3. 使用请求
    std::string body;
    // std::string path = webRoot;
    // path += req.url_; //"wwwroot/a/b/c.html"，在解析的时候加了，可以不要了
    Util::ReadFile(req.path_, &body);//放入body中

    std::string response = "HTTP/1.0 200 OK" + SEP;
    response += "Content-Length: " + std::to_string(body.size()) + SEP;
    // response += "Content-Type:text/html" + SEP;
    response += GetContentType(req.suffix_);//根据后缀，封装一个GetContentType
    response += SEP;
    response += body;
    return response;
}

int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        exit(USAGE_ERR);
    }
    uint16_t port = atoi(argv[1]);
    std::unique_ptr<HttpServer> tsvr(new HttpServer(HandlerHttp)); // TODO
    tsvr->InitServer();
    tsvr->Start();

    return 0;
}
